//Class that represents a 64-bit word
//Internaly bit0 is the least significant bit 
//and bit63 is the most significant bit
// 
//The word can be initiated through different constructors
//For output conversions to hexadecimal or binary string are supported

#include "word64.h"

//initiate w to the value given by the input string
//The string hould be encoded with LSB first
//It is also assumed that the length of the string is not longer than 64-bits
//But shorter is ok
word64::word64(std::string inputString){
  //initiate w to 0
  w=0;
  //copy bits from inputString
  for(unsigned i=0;i<inputString.size();i++){
    if(inputString[i]=='1')
      setBit(i);
  }
}

//assign w to the value given by the input string
//The string hould be encoded with LSB first
//It is also assumed that the length of the string is not longer than 64-bits
//But shorter is ok
void word64::assign(std::string inputString){
  //initiate w to 0
  w=0;
  //copy bits from inputString
  for(unsigned i=0;i<inputString.size();i++){
    if(inputString[i]=='1')
      setBit(i);
  }
}

//return the word encoded as a string
//binary representation with the least significant bit first
std::string word64::toBinStringLSB(){
  std::string s;
  uint64_t w2=w; //copy the word
  //extract least significant bit from w2
  //shift to remove least significant bit
  //and repeat for new least significant bit
  for(int i=0;i<64;i++){
    if((w2&1)==0)
      s+='0';
    else
      s+='1';
    w2>>=1;
  }
  return s;
}

//return the word encoded as a string
//binary representation with the most significant bit first
std::string word64::toBinStringMSB(){
  //create w2 as the same word as w but bit ordering reversed
  word64 w2;
  for(int i=0;i<64;i++)
    w2.setVal((63-i),getBit(i));
  //w with MSB first is the same as w2 with LSB
  return w2.toBinStringLSB();
}

//return the word encoded as a string
//hexadecimal representation with the  most significant bit first
std::string word64::toHexStringMSB(){
  std::string s1="0123456789ABCDEF"; //hexadecimal characters
  std::string s2="";
  //mask 4 consecutive bits
  //starting with 4 most significant bits
  s2+=s1[(w>>60)&15]; 
  s2+=s1[(w>>56)&15];
  s2+=s1[(w>>52)&15];
  s2+=s1[(w>>48)&15];
  s2+=s1[(w>>44)&15];
  s2+=s1[(w>>40)&15];
  s2+=s1[(w>>36)&15];
  s2+=s1[(w>>32)&15];
  s2+=s1[(w>>28)&15]; 
  s2+=s1[(w>>24)&15];
  s2+=s1[(w>>20)&15];
  s2+=s1[(w>>16)&15];
  s2+=s1[(w>>12)&15];
  s2+=s1[(w>>8)&15];
  s2+=s1[(w>>4)&15];
  s2+=s1[(w&15)];
  return s2;
}

//return the word encoded as a string
//hexadecimal representation with the  least significant bit first
std::string word64::toHexStringLSB(){
  //w with MSB first is the same as w2 with LSB  
  word64 w2;
  for(int i=0;i<64;i++)
    w2.setVal((63-i),getBit(i));
  return w2.toHexStringMSB();
}

//calculates the number of 1 in the word
int word64::weight(){
  //using the popcount algorithm to calculate the weight
  uint64_t wht=(w&0x5555555555555555uLL)+ ((w>>1)&0x5555555555555555uLL); //2-bit
  wht=(wht&0x3333333333333333uLL)+ ((wht>>2)&0x3333333333333333uLL); //4-bit
  wht=(wht&0x0f0f0f0f0f0f0f0fuLL)+ ((wht>>4)&0x0f0f0f0f0f0f0f0fuLL); //8-bit
  wht=(wht&0x00ff00ff00ff00ffuLL)+ ((wht>>8)&0x00ff00ff00ff00ffuLL); //16-bit
  wht=(wht&0x0000ffff0000ffffuLL)+ ((wht>>16)&0x0000ffff0000ffffuLL); //32-bit
  wht=(wht&0x00000000ffffffffuLL)+ ((wht>>32)&0x00000000ffffffffuLL); //64-bit
  return (int)wht;
}
